package connection

import (
	"sync"
	"time"
	"unsafe"

	"chat.com/library"
	"chat.com/pkg/logger"
)

var ConnectionManagerInstance = NewConnectionManager()

// 用户连接管理器, 用于管理所有的用户连接
type ConnectionManager struct {
	Visitors       map[string]*Connection // 游客的连接池
	VisitorsRWLock sync.RWMutex           // 读写锁
	Users          map[string]*Connection // 用户的连接池 // appId+uuid
	UserRWLock     sync.RWMutex           // 读写锁

	RegisterVisitorCh   chan *Connection // 游客连接处理
	UnregisterVisitorCh chan *Connection // 游客断开连接处理
	LoginCh             chan *Connection // 用户登录处理
	LogoutCh            chan *Connection // 用户退出登录处理
	BroadcastCh         chan []byte      // 广播 向全部成员发送数据
}

func NewConnectionManager() (connectionManager *ConnectionManager) {
	connectionManager = &ConnectionManager{
		Visitors:            make(map[string]*Connection),
		Users:               make(map[string]*Connection),
		RegisterVisitorCh:   make(chan *Connection, 100),
		UnregisterVisitorCh: make(chan *Connection, 100),
		LoginCh:             make(chan *Connection, 100),
		LogoutCh:            make(chan *Connection, 100),
		BroadcastCh:         make(chan []byte, 100),
	}

	return
}

/**************************  manager  ***************************************/

// Size 获取ConnectionManager占内存大小
func (manager *ConnectionManager) Size() (size int64) {
	size1 := unsafe.Sizeof(*manager)
	size = int64(size1)
	return
}

// 判断是否是游客
func (manager *ConnectionManager) IsVisitor(visitor string) (ok bool) {
	manager.VisitorsRWLock.RLock()
	defer manager.VisitorsRWLock.RUnlock()

	_, ok = manager.Visitors[visitor]
	return
}

// GetVisitors 获取所有游客连接
func (manager *ConnectionManager) GetAllVisitor() (connections map[string]*Connection) {
	connections = make(map[string]*Connection)
	manager.VisitorRange(func(visitor string, connection *Connection) (result bool) {
		connections[visitor] = connection
		return true
	})

	return
}

// VisitorsRange 遍历游客连接, 对每一个游客连接执行自定义的fn函数
func (manager *ConnectionManager) VisitorRange(fn func(visitor string, connection *Connection) (result bool)) {
	manager.VisitorsRWLock.RLock()
	defer manager.VisitorsRWLock.RUnlock()

	for key, value := range manager.Visitors {
		result := fn(key, value)
		if result == false {
			return
		}
	}

	return
}

// GetVisitorTotalNumber 获取当前用户数
func (manager *ConnectionManager) GetVisitorTotalNumber() (num int) {
	num = len(manager.Visitors)
	return
}

// 获取游客连接
func (manager *ConnectionManager) GetVisitor(visitor string) (connection *Connection) {
	manager.VisitorsRWLock.RLock()
	defer manager.VisitorsRWLock.RUnlock()

	if value, ok := manager.Visitors[visitor]; ok {
		connection = value
	}

	return
}

// 添加游客连接
func (manager *ConnectionManager) AddVisitor(connection *Connection) {
	manager.VisitorsRWLock.Lock()
	defer manager.VisitorsRWLock.Unlock()

	manager.Visitors[connection.Addr] = connection
}

// 删除游客连接
func (manager *ConnectionManager) RemoveVisitor(connection *Connection) {
	manager.VisitorsRWLock.Lock()
	defer manager.VisitorsRWLock.Unlock()

	if _, ok := manager.Visitors[connection.Addr]; ok {
		delete(manager.Visitors, connection.Addr)
	}
}

/*************************************************************************************************************************8*/
// 获取用户连接
func (manager *ConnectionManager) GetUser(appId int64, userId int64) (connection *Connection) {
	manager.UserRWLock.RLock()
	defer manager.UserRWLock.RUnlock()

	userKey := library.GetUserKey(appId, userId)
	if value, ok := manager.Users[userKey]; ok {
		connection = value
	}

	return
}

// GetUserTotalNumber 获取当前用户数
func (manager *ConnectionManager) GetUserTotalNumber() (userLen int) {
	userLen = len(manager.Users)
	return
}

// 添加用户连接
func (manager *ConnectionManager) AddUser(connection *Connection) {
	manager.UserRWLock.Lock()
	defer manager.UserRWLock.Unlock()

	userKey := library.GetUserKey(connection.AppId, connection.UserId)
	manager.Users[userKey] = connection
}

// 删除用户连接
func (manager *ConnectionManager) RemoveUser(connection *Connection) (result bool) {
	manager.UserRWLock.Lock()
	defer manager.UserRWLock.Unlock()

	key := library.GetUserKey(connection.AppId, connection.UserId)
	if value, ok := manager.Users[key]; ok {
		// 判断是否为相同的用户
		if value.Addr != connection.Addr {
			return
		}
		delete(manager.Users, key)
		result = true
	}

	return
}

// 获取用户的key
func (manager *ConnectionManager) GetUserKeys() (userKeys []string) {
	userKeys = make([]string, 0)

	manager.UserRWLock.RLock()
	defer manager.UserRWLock.RUnlock()

	for key := range manager.Users {
		userKeys = append(userKeys, key)
	}

	return
}

// 获取特定app平台用户信息
func (manager *ConnectionManager) GetUserList(appId int64) (userList []int64) {
	userList = make([]int64, 0)

	manager.UserRWLock.RLock()
	defer manager.UserRWLock.RUnlock()

	for _, v := range manager.Users {
		if v.AppId == appId {
			userList = append(userList, v.UserId)
		}
	}

	logger.Debug("GetUserList len:", len(manager.Users))
	return
}

// 获取所有用户连接
func (manager *ConnectionManager) GetAllUserConnection() (connections []*Connection) {
	connections = make([]*Connection, 0)

	manager.UserRWLock.RLock()
	defer manager.UserRWLock.RUnlock()

	for _, conn := range manager.Users {
		connections = append(connections, conn)
	}

	return
}

// 向全部成员发送数据
func (manager *ConnectionManager) sendAll(message []byte) {
	connections := manager.GetAllUserConnection()
	for _, conn := range connections {
		conn.SendMessage(message)
	}
}

// 向特定app平台全部成员发送数据
func (manager *ConnectionManager) sendPlatformAll(message []byte, appId int64) {
	connections := manager.GetAllUserConnection()
	for _, conn := range connections {
		if conn.AppId == appId {
			conn.SendMessage(message)
		}
	}
}

// 游客建立连接事件
func (manager *ConnectionManager) EventRegister(connection *Connection) {
	manager.AddVisitor(connection)
	logger.Debug("EventRegister 游客建立连接", connection.Addr)
}

// 游客断开连接事件
func (manager *ConnectionManager) EventUnregister(connection *Connection) {
	manager.RemoveVisitor(connection)
	logger.Debug("EventUnregister 游客断开连接", connection.Addr, connection.AppId, connection.UserId)
}

// 用户登录事件
func (manager *ConnectionManager) EventLogin(connection *Connection) {
	manager.AddUser(connection)
	logger.Debug("EventLogin 用户登录 %s, %d, %d", connection.Addr, connection.AppId, connection.UserId)
}

// 用户退出登录事件
func (manager *ConnectionManager) EventLogout(connection *Connection) {
	manager.RemoveUser(connection)
	logger.Debug("EventLogout 用户退出登录 %s, %d, %d", connection.Addr, connection.AppId, connection.UserId)
}

// 管道处理程序
func (manager *ConnectionManager) Start() {
	for {
		select {
		case conn := <-manager.RegisterVisitorCh:
			// 游客建立连接事件
			manager.EventRegister(conn)

		case conn := <-manager.UnregisterVisitorCh:
			// 游客断开连接事件
			manager.EventUnregister(conn)

		case login := <-manager.LoginCh:
			// 用户登录事件
			manager.EventLogin(login)

		case login := <-manager.LogoutCh:
			// 用户退出登录事件
			manager.EventLogin(login)

		case message := <-manager.BroadcastCh:
			// 对全体用户广播事件
			connections := manager.GetAllUserConnection()
			for _, conn := range connections {
				conn.SendMessage(message)
			}
		}
	}
}

/**************************  manager info  ***************************************/
// 获取管理者信息
func GetManagerInfo(isDebug string) (managerInfo map[string]interface{}) {

	managerInfo = make(map[string]interface{})

	managerInfo["visitorTotal"] = ConnectionManagerInstance.GetVisitorTotalNumber()       // 当前游客连接数
	managerInfo["usersTotal"] = ConnectionManagerInstance.GetUserTotalNumber()            // 当前用户数
	managerInfo["chanRegisterLen"] = len(ConnectionManagerInstance.RegisterVisitorCh)     // 未处理游客连接事件数
	managerInfo["chanUnregisterLen"] = len(ConnectionManagerInstance.UnregisterVisitorCh) // 未处理游客断开连接事件数
	managerInfo["chanLoginLen"] = len(ConnectionManagerInstance.LoginCh)                  // 未处理用户登录事件数
	managerInfo["chanLogoutLen"] = len(ConnectionManagerInstance.LogoutCh)                // 未处理用户退出登录事件数
	managerInfo["chanBroadcastLen"] = len(ConnectionManagerInstance.BroadcastCh)          // 未处理广播事件数

	if isDebug == "true" {
		addrList := make([]string, 0)
		ConnectionManagerInstance.VisitorRange(func(visitor string, connection *Connection) (result bool) {
			addrList = append(addrList, connection.Addr)
			return true
		})

		users := ConnectionManagerInstance.GetUserKeys()

		managerInfo["connections"] = addrList // 客户端列表
		managerInfo["users"] = users          // 登录用户列表
	}

	return
}

// 获取用户的连接
func GetUserConnection(appId int64, userId int64) (connection *Connection) {
	connection = ConnectionManagerInstance.GetUser(appId, userId)
	return
}

// 获取全部用户
func GetUserList(appId int64) (userList []int64) {
	logger.Debug("获取全部用户", appId)
	userList = ConnectionManagerInstance.GetUserList(appId)
	return
}

// 全员广播
func AllSendMessages(appId int64, senderId int64, data string) {
	logger.Debug("全员广播", appId, senderId, data)
	ConnectionManagerInstance.sendPlatformAll([]byte(data), appId)
}

func CheckConnectionManagerInstance() {

	for {
		ConnectionManagerInstance.UserRWLock.RLock()
		logger.Debug("当前有%d个用户连接\n", len(ConnectionManagerInstance.Users))
		logger.Debug("", ConnectionManagerInstance.GetAllUserConnection())
		logger.Debug("当前有%d个用户连接\n", len(ConnectionManagerInstance.Users))
		ConnectionManagerInstance.UserRWLock.RUnlock()

		time.Sleep(5 * time.Second)
	}
}

// 定时清理超时连接
func ClearTimeoutConnections() {

	currentTime := uint64(time.Now().Unix())

	connections := ConnectionManagerInstance.GetAllUserConnection()
	for _, connection := range connections {
		if connection.IsHeartbeatTimeout(currentTime) {
			logger.Debug("心跳时间超时 关闭连接", connection.Addr, connection.UserId, connection.LoginTime, connection.HeartbeatTime)
			connection.WsConn.Close()
		}
	}
}
